package com.spring.future.common.utils;


import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public class Collections3 {
	private static Logger logger = LoggerFactory.getLogger(Collections3.class);

	public static <E> List<E> extractToList(final Collection collection, final String propertyName) {
		if (isEmpty(collection)) {
			return Lists.newArrayList();
		}
		List<E> list = new ArrayList(collection.size());
		try {
			for (Object obj : collection) {
				list.add((E) PropertyUtils.getProperty(obj, propertyName));
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return list;
	}

	public static <K,V> Map<K,V> extractToMap(final Collection collection, final String keyPropertyName) {
		if (isEmpty(collection)) {
			return Maps.<K,V>newHashMap();
		}
		Map<K,V> map = new HashMap<K,V>(collection.size());
		try {
			for (Object obj : collection) {
				map.put((K)PropertyUtils.getProperty(obj, keyPropertyName), (V)obj);
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return map;
	}


	/**
	 * 返回a+b的新List.
	 */
	public static <T> List<T> union(final Collection<T> a, final Collection<T> b) {
		List<T> result = new ArrayList<T>(a);
		result.addAll(b);
		return result;
	}

	/**
	 * 返回a-b的新List.
	 */
	public static <T> List<T> subtract(final Collection<T> a, final Collection<T> b) {
		List<T> list = new ArrayList<T>(a);
		for (T element : b) {
			list.remove(element);
		}

		return list;
	}

	/**
	 * 返回a与b的交集的新List.
	 */
	public static <T> List<T> intersection(Collection<T> a, Collection<T> b) {
		List<T> list = new ArrayList<T>();
		for (T element : a) {
			if (b.contains(element)) {
				list.add(element);
			}
		}
		return list;
	}


	/**
	 * 提取集合中的对象的两个属性(通过Getter函数), 组合成Map.
	 *
	 * @param collection
	 *            来源集合.
	 * @param keyPropertyName
	 *            要提取为Map中的Key值的属性名.
	 * @param valuePropertyName
	 *            要提取为Map中的Value值的属性名.
	 */
	public static Map extractToMap(final Collection collection, final String keyPropertyName, final String valuePropertyName) {
		if (isEmpty(collection)) {
			return Maps.newHashMap();
		}
		Map map = new HashMap(collection.size());
		try {
			for (Object obj : collection) {
				map.put(PropertyUtils.getProperty(obj, keyPropertyName), PropertyUtils.getProperty(obj, valuePropertyName));
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}

		return map;
	}

	public static Set extractToSet(final Collection collection, final String propertyName) {
		if (isEmpty(collection)) {
			return Sets.newHashSet();
		}
		Set set = new LinkedHashSet();
		try {
			for (Object obj : collection) {
				set.add(PropertyUtils.getProperty(obj, propertyName));
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return set;
	}

	public static <P,C> List<P>  joinChildList(List<P> parentList, List<C> childList, Class parentChildClass) {
		String parentKeyField = "id";
		String parentChildField = WordUtils.uncapitalize(parentChildClass.getSimpleName() + "List");
		String childParentKeyFiled =WordUtils.uncapitalize(parentList.get(0).getClass().getSimpleName() + "Id");
		return joinChildList(parentList,childList,parentKeyField,parentChildField,childParentKeyFiled);
	}


	public static <P,C> List<P>  joinChildList(List<P> parentList, List<C> childList, String parentKeyField,String parentChildField, String childParentKeyFiled) {
		Map<Object,Collection<C>> childMap = Maps.newHashMap();
		try {
			for(C item:childList) {
				Object key = ReflectionUtils.getFieldValue(item,childParentKeyFiled);
				if(!childMap.containsKey(key)) {
					childMap.put(key,Lists.<C>newArrayList());
				}
				childMap.get(key).add(item);
			}
			for(P item:parentList) {
				Object key =ReflectionUtils.getFieldValue(item,parentKeyField);
				if(childMap.containsKey(key)) {
					Collection<C> property = (Collection<C>)ReflectionUtils.getFieldValue(item,parentChildField);
					property.addAll(childMap.get(key));
				}
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return parentList;
	}

	public static <P,C> List<P>  joinChild(List<P> parentList, List<C> childList,  Class parentChildClass) {
		String parentChildField =  WordUtils.uncapitalize(parentChildClass.getSimpleName());
		String parentChildKeyField = parentChildField + "Id";
		String childKeyField = "id";
		return joinChild(parentList,childList,parentChildField,parentChildKeyField,childKeyField);
	}

	public static <P,C> List<P>  joinChild(List<P> parentList, List<C> childList, String parentChildField,String parentChildKeyField, String childKeyField) {
		Map<Object,C> childMap = Maps.newHashMap();
		try {
			for(C item:childList) {
				Object key = ReflectionUtils.getFieldValue(item,childKeyField);
				childMap.put(key,item);
			}
			for(P item:parentList) {
				Object key = ReflectionUtils.getFieldValue(item,parentChildKeyField);
				if(childMap.containsKey(key)) {
					ReflectionUtils.setFieldValue(item,parentChildField,childMap.get(key));
				}
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
		return parentList;
	}


	public static boolean isEmpty(Collection collection) {
		return (collection == null) || collection.isEmpty();
	}

	public static boolean isEmpty(Map map) {
		return (map == null) || map.isEmpty();
	}

	public static boolean isNotEmpty(Collection collection) {
		return !isEmpty(collection);
	}

	public static boolean isNotEmpty(Map map) {
		return !isEmpty(map);
	}


}
